#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "extractpdf.h"
#include "imageutils.h"

#include <memory>
#include <iostream>
#include <iomanip>

#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QImage>
#include <QMessageBox>
#include <QPainter>

#include <QFuture>
#include <QThreadPool>
#include <QtConcurrent/QtConcurrent>

// Poppler PDF库
#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-image.h>
#include <poppler/cpp/poppler-page.h>
#include <poppler/cpp/poppler-page-renderer.h>
#include <QtGlobal>
#include <QAtomicInteger>  // Qt6
#include <QAtomicInt>      // Qt5
#include <QtConcurrent>

#define kuserocr 1
#if kuserocr
#include <cstdio>
#include "OcrLite.h"
#include "OcrUtils.h"
#ifdef _WIN32
#include <windows.h>
#endif
#endif


bool showcontent = false;
// bool showcontent = true;
#define kUseMultiThread 1
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::ocr(std::string imgDir,std::string imgName){
#if kuserocr
    int numThread = 4;
    int padding = 50;
    int maxSideLen = 1024;
    float boxScoreThresh = 0.5f;
    float boxThresh = 0.3f;
    float unClipRatio = 1.6f;
    bool doAngle = true;
    int flagDoAngle = 1;
    bool mostAngle = true;
    int flagMostAngle = 1;
    int flagGpu = -1;

    OcrLite ocrLite;
    ocrLite.setNumThread(numThread);
    ocrLite.initLogger(
        true,//isOutputConsole
        false,//isOutputPartImg
        true);//isOutputResultImg

    ocrLite.enableResultTxt(imgDir.c_str(), imgName.c_str());
    ocrLite.setGpuIndex(flagGpu);
    ocrLite.Logger("=====Input Params=====\n");
    ocrLite.Logger(
        "numThread(%d),padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d),GPU(%d)\n",
        numThread, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle,
        flagGpu);
    QString qmodelDetPath = ":/ocr/det_model";
    QString qmodelClsPath = ":/ocr/cls_model";
    QString qmodelRecPath = ":/ocr/rec_model";
    QString qkeysPath = ":/ocr/txt_model";
    std::string modelDetPath = qmodelDetPath.toStdString();
    std::string modelClsPath = qmodelClsPath.toStdString();
    std::string modelRecPath = qmodelRecPath.toStdString();
    std::string keysPath = qkeysPath.toStdString();
    ocrLite.initModels(modelDetPath, modelClsPath, modelRecPath, keysPath);

    OcrResult result = ocrLite.detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen,
                                      boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
#endif
}
bool MainWindow::dealStaticPDF(QString filePath) {
    qDebug() << "begin dealStaticPDF :" << filePath;
    
    // Get output path by removing file extension
    QFileInfo fileInfo(filePath);
    QString outPath = fileInfo.absolutePath() + "/" + fileInfo.baseName() + "/";
    
    // Create output directory if it doesn't exist
    QDir dir(outPath);
    if (!dir.exists()) {
        dir.mkpath(".");
    }
    
    bool success = PdfExtractor::extractAllPdfTextAndImages(
        filePath.toStdString(),
        [this, outPath](int pageNumber, ContentType type, const char* content, const char* ext) -> bool {
            if (type == ContentType::content_text) {
                if (showcontent) {
                    // std::string text = content;
                    // QString savePath = outPath + "/page_" + QString::number(pageNumber) + ".txt";
                    // QFile file(savePath);
                    // if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
                    //     QTextStream out(&file);
                    //     out << QString::fromStdString(text);
                    //     file.close();
                    // }
                    // qDebug() << "Page:" << pageNumber << "Text saved to:" << savePath;
                }
            } else if (type == ContentType::content_img) {
                std::string filename = content;
                QString imgPath = QString::fromStdString(filename);
                //ocr(outPath.toStdString(), imgPath.toStdString());
                qDebug() << "Page:" << pageNumber << "Image processed:" << imgPath;
            }
            return true; // Continue processing next page
        },
        PdfExtractor::ExtractionMode::TextAndImages,
        outPath.toStdString()
    );
    
    return success;
}
bool MainWindow::dealInstancePDF(QString filePath){
    qDebug() << "begin dealInstancePDF :" << filePath;
    PdfExtractor extractor;

    if (!extractor.setupFilePath(filePath.toStdString())) {
        qCritical() << "Failed to setup PDF file path";
        return false;
    }

    int pageCount = extractor.getPageCount();
    qDebug() << "Total pages:" << pageCount;

    for (int i = 0; i < pageCount; ++i) {
        bool success = extractor.extractPdfTextAndImagesFromPage(
            i,
            [i](int pageNumber, ContentType type, const char* content , const char* ext) -> bool {
                if (type == ContentType::content_text) {
                    std::string text = content;
                    if (showcontent) {
                        qDebug() << "Page" << pageNumber << "Text:" << QString::fromStdString(text);
                    }
                } else if (type == ContentType::content_img) {
                    std::string filename = content;
                    qDebug() << "Page:" << pageNumber << "Image:" << QString::fromStdString(filename);
                }
                return true; // 继续处理下一个内容
            },
            PdfExtractor::ExtractionMode::TextAndImages
            );

        if (!success) {
            qWarning() << "Failed to extract content from page" << i + 1;
        }
    }
}

void MainWindow::processMultiFiles(const QFileInfoList& fileList,
                                   std::function<bool(const QString&)> processor,
                                   int threadCount) {
    int totalFiles = fileList.size();

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
    QAtomicInteger<int> processedCount(0);
#else
    QAtomicInt processedCount(0);
#endif

    QThreadPool::globalInstance()->setMaxThreadCount(threadCount);  //

    QtConcurrent::map(fileList, [&](const QFileInfo& fileInfo) {
        QString fileName = fileInfo.absoluteFilePath();

        // 跨版本原子操作
        int currentCount;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
        currentCount = processedCount.loadRelaxed();  //
#else
        currentCount = processedCount.load();  //
#endif


        bool success = processor(fileName);

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
        processedCount.fetchAndAddRelaxed(1);  //
#else
        processedCount.fetchAndAddRelaxed(1);  //
#endif
        qDebug() << "Total:" << totalFiles
                 << "Current:" << currentCount
                 << "Processing:" << fileName;
        qDebug() << (success ? "Success" : "Failed") << fileName;
    }).waitForFinished();  //
}
void MainWindow::processOneByOneFiles(const QFileInfoList& fileList,
                                      std::function<bool(const QString&)> processor) {
    int totalFiles = fileList.size();

    int processedCount = 0;
    for (const QFileInfo& fileInfo : fileList) {
        processedCount++;
        QString fileName = fileInfo.absoluteFilePath();
        qDebug() << "Total:" << totalFiles
                 << "Current:" << processedCount
                 << "Processing:" << fileName;

        bool success = processor(fileName);
        // processedCount.fetchAndAddRelaxed(1);
        qDebug() << (success ? "Success" : "Failed") << fileName;
    }
}
void MainWindow::processPDFFiles(const QString& dirPath,
                                 std::function<bool(const QString&)> processor,
                                 int threadCount) {
    QDir dir(dirPath);
    QStringList filters{"*.pdf"};
    dir.setNameFilters(filters);
    QFileInfoList fileList = dir.entryInfoList(QDir::Files);

    if (fileList.isEmpty()) {
        qDebug() << "No PDF files found in" << dirPath;
        return;
    }
    processMultiFiles(fileList, processor, threadCount);
    // processOneByOneFiles(fileList,processor);


}

void MainWindow::on_pushButton_single_static_clicked()
{
    // QStringList pdfFiles = {
    //     "D:/PDF/b352d71d80f3464a8ccac15804deb2d2.pdf",
    //     "D:/PDF/b7f10a5002d742d1bc8fad89bf8b2ecb.pdf",
    //     "D:/PDF/b70b4424-dd68-4939-bf48-91ef0fa63787.pdf",
    //     "D:/PDF/b716680ff0bf4278877ae2e3203fa8ab.pdf"
    // };


    QStringList pdfFiles= {
        "E:/workspace/work/PDF/我国实现“双碳”目标面临的挑战及对策_庄贵阳.pdf"
        // "E:/workspace/work/PDF/1711508565229086593.pdf" ,
        // "E:/workspace/work/PDF/e9220377d3cf4826b97303f8e5220ee1.pdf"
    };


    for (const QString &fileName : pdfFiles) {
        bool success = dealStaticPDF(fileName);
        qDebug() << (success ? "Success" : "Failed") << "processing" << fileName;
    }

}

void MainWindow::on_pushButton_single_instance_clicked()
{

    QStringList pdfFiles = {
        "D:/PDF/b352d71d80f3464a8ccac15804deb2d2.pdf",
        "D:/PDF/b7f10a5002d742d1bc8fad89bf8b2ecb.pdf",
        "D:/PDF/b70b4424-dd68-4939-bf48-91ef0fa63787.pdf",
        "D:/PDF/b716680ff0bf4278877ae2e3203fa8ab.pdf"
    };

    for (const QString &fileName : pdfFiles) {
        bool success = dealInstancePDF(fileName);
        qDebug() << (success ? "Success" : "Failed") << "processing" << fileName;
    }

}
void MainWindow::on_pushButton_bat_static_clicked() {
    QString path = "e:\\workspace\\work\\PDF\\";
    path = "D:\\workspace\\PDF\\";
    processPDFFiles(path,
                    [this](const QString& path){
                        return dealStaticPDF(path);
                    },
                    32);  // 静态处理单线程
}

void MainWindow::on_pushButton_bat_instance_clicked() {
    processPDFFiles("e:\\workspace\\work\\PDF\\",
                    [this](const QString& path){
                        return dealInstancePDF(path);
                    },
                    8);  // 实例处理多线程
}


